#include "GameObject.h"
#include "../Camera/Camera.h"
#include "../Renderer/TextureRenderer.h"
#include <graphics.h>
#include <algorithm>
#include <iostream>
#include <memory>
#include <cmath>
#pragma comment(lib,"MSIMG32.LIB")

// Rigidbody gravity constant
const float Rigidbody::GRAVITY = 980.0f; // pixels/sec²

// Static camera for rendering
Camera* Renderer::s_renderingCamera = nullptr;

// GameObject implementation
GameObject::GameObject(const std::string& name)
    : name_(name), active_(true), collisionBox_(nullptr) {
    // Every GameObject must have a Transform component
    transform_ = addComponent<Transform>();
}

GameObject::~GameObject() = default;

void GameObject::update(float deltaTime) {
    if (!active_) return;

    for (auto& component : components_) {
        if (component->isEnabled()) {
            component->update(deltaTime);
        }
    }
    // Update collision box position if it exists
    if (collisionBox_ && transform_) {
        // Update collision box position to match transform
        // This assumes the collision box should match the transform bounds
        if (auto rectBox = std::dynamic_pointer_cast<RectangleCollisionBox>(collisionBox_)) {
            rectBox->setX(transform_->getX());
            rectBox->setY(transform_->getY());
            rectBox->setWidth(transform_->getWidth());
            rectBox->setLength(transform_->getHeight()); // Note: setLength is used for height
        }
    }
}

void GameObject::render() {
    if (!active_) return;

    for (auto& component : components_) {
        if (component->isEnabled()) {
            component->render();
        }
    }
}

void GameObject::setCollisionBox(std::shared_ptr<CollisionBox> collisionBox) {
    collisionBox_ = collisionBox;
}

std::shared_ptr<CollisionBox> GameObject::getCollisionBox() const {
    return collisionBox_;
}

bool GameObject::checkCollision(const GameObject& other) const {
    if (!collisionBox_ || !other.collisionBox_) {
        return false;
    }
    return collisionBox_->checkCollision(*other.collisionBox_);
}

// Transform implementation
Transform::Transform(GameObject* gameObject)
    : Component(gameObject), x_(0), y_(0), width_(50), height_(50), rotation_(0) {}

void Transform::setPosition(float x, float y) {
    x_ = x;
    y_ = y;

    // Update collision box position
    auto collisionBox = gameObject_->getCollisionBox();
    if (collisionBox) {
        switch (collisionBox->getType()) {
        case CollisionBoxType::Rectangle: {
            auto rect = static_cast<RectangleCollisionBox*>(collisionBox.get());
            rect->setX(x);
            rect->setY(y);
            break;
        }
        case CollisionBoxType::Circle: {
            auto circle = static_cast<CircleCollisionBox*>(collisionBox.get());
            circle->setX(x + width_ / 2);
            circle->setY(y + height_ / 2);
            break;
        }
        case CollisionBoxType::Point: {
            auto point = static_cast<PointCollisionBox*>(collisionBox.get());
            point->setX(x + width_ / 2);
            point->setY(y + height_ / 2);
            break;
        }
        }
    }
}

void Transform::translate(float deltaX, float deltaY) {
    setPosition(x_ + deltaX, y_ + deltaY);
}

void Transform::setSize(float width, float height) {
    width_ = width;
    height_ = height;

    // Update collision box size
    auto collisionBox = gameObject_->getCollisionBox();
    if (collisionBox && collisionBox->getType() == CollisionBoxType::Rectangle) {
        auto rect = static_cast<RectangleCollisionBox*>(collisionBox.get());
        rect->setWidth(width);
        rect->setLength(height);
    }
}

// Renderer implementation
Renderer::Renderer(GameObject* gameObject) : Component(gameObject), color_(WHITE) {}
int Renderer::s_direction = 1;

//透明通道混叠 

inline void putimage_alpha(int x, int y, IMAGE* img) {
    int w = img->getwidth();
    int h = img->getheight();
    AlphaBlend(GetImageHDC(NULL), x, y, w, h,
        GetImageHDC(img), 0, 0, w, h, { AC_SRC_OVER,0,255,AC_SRC_ALPHA });

}

void Renderer::render() {
    if (!enabled_) return;

    Transform* transform = gameObject_->getTransform();
    if (!transform) return;

    setfillcolor(color_);
    setlinecolor(color_);

    // Get world position
    float worldX = transform->getX();
    float worldY = transform->getY();
    float width = transform->getWidth();
    float height = transform->getHeight();

    // Transform to screen coordinates if camera is available
    float screenX = worldX;
    float screenY = worldY;

    if (s_renderingCamera) {
        screenX = s_renderingCamera->worldToScreenX(worldX);
        screenY = s_renderingCamera->worldToScreenY(worldY);
    }

    // Draw filled rectangle
    /*fillrectangle(
        static_cast<int>(screenX),
        static_cast<int>(screenY),
        static_cast<int>(screenX + width),
        static_cast<int>(screenY + height)
    );*/

    IMAGE image;
    
    if (s_direction == 0) {
        loadimage(&image, L"lumv2/Game_engine_demo_v1/assets/textures/player_left.png", width * 1.4, height);
    }
    else {
        loadimage(&image, L"lumv2/Game_engine_demo_v1/assets/textures/player_right.png", width * 1.4, height);
    }
    putimage_alpha(static_cast<int>(screenX), static_cast<int>(screenY), &image);

    
}

// Rigidbody implementation
Rigidbody::Rigidbody(GameObject* gameObject)
    : Component(gameObject), velocityX_(0), velocityY_(0), prevX_(0), prevY_(0), useGravity_(true), grounded_(false) {}

void Rigidbody::setVelocity(float vx, float vy) {
    velocityX_ = vx;
    velocityY_ = vy;
}

void Rigidbody::addVelocity(float vx, float vy) {
    velocityX_ += vx;
    velocityY_ += vy;
}

void Rigidbody::update(float deltaTime) {
    if (!enabled_) return;

    Transform* transform = gameObject_->getTransform();
    if (!transform) return;

    // Store previous position
    prevX_ = transform->getX();
    prevY_ = transform->getY();

    // Apply gravity
    if (useGravity_ && !grounded_) {
        velocityY_ += GRAVITY * deltaTime;
    }

    // Limit maximum velocity to prevent tunneling
    const float MAX_VELOCITY = 1000.0f; // Maximum pixels per second
    if (velocityY_ > MAX_VELOCITY) {
        velocityY_ = MAX_VELOCITY;
    }
    if (velocityY_ < -MAX_VELOCITY) {
        velocityY_ = -MAX_VELOCITY;
    }
    if (velocityX_ > MAX_VELOCITY) {
        velocityX_ = MAX_VELOCITY;
    }
    if (velocityX_ < -MAX_VELOCITY) {
        velocityX_ = -MAX_VELOCITY;
    }

    // Calculate movement for this frame
    float deltaX = velocityX_ * deltaTime;
    float deltaY = velocityY_ * deltaTime;

    // For high-speed movement, use sub-stepping to prevent tunneling
    const float MAX_MOVEMENT_PER_STEP = 20.0f; // Maximum pixels per sub-step
    float totalDeltaX = deltaX;
    float totalDeltaY = deltaY;

    // Calculate number of sub-steps needed
    float maxMovement = (std::max)(std::abs(totalDeltaX), std::abs(totalDeltaY));
    int subSteps = 1;
    if (maxMovement > MAX_MOVEMENT_PER_STEP) {
        subSteps = static_cast<int>(std::ceil(maxMovement / MAX_MOVEMENT_PER_STEP));
    }

    // Perform sub-stepping
    float stepDeltaX = totalDeltaX / subSteps;
    float stepDeltaY = totalDeltaY / subSteps;

    for (int step = 0; step < subSteps; ++step) {
        float currentX = transform->getX();
        float currentY = transform->getY();
        float newX = currentX + stepDeltaX;
        float newY = currentY + stepDeltaY;

        transform->setPosition(newX, newY);

        // World boundary detection (use reasonable world limits)
        const float WORLD_WIDTH = 2000.0f;  // Match the world width from PlatformJumpScene
        const float WORLD_HEIGHT = 800.0f;  // Match the world height from PlatformJumpScene

        // Left and right world boundaries
        if (newX < 0) {
            transform->setPosition(0, transform->getY());
            velocityX_ = 0;
        }
        else if (newX + transform->getWidth() > WORLD_WIDTH) {
            transform->setPosition(WORLD_WIDTH - transform->getWidth(), transform->getY());
            velocityX_ = 0;
        }

        // Only handle ground collision if collision system doesn't handle it
        if (newY + transform->getHeight() > WORLD_HEIGHT) {
            transform->setPosition(transform->getX(), WORLD_HEIGHT - transform->getHeight());
            velocityY_ = 0;
            grounded_ = true;
            break; // Stop sub-stepping if we hit the ground
        }

        // If collision system will handle collision checking, break here
        // The collision system will need to handle each sub-step appropriately
    }
    // Note: Don't automatically set grounded_ = false here, 
    // let the collision detection system handle ground state
}
